/*
 * This file is part of Catfish.
 * Copyright (C) 2010 Namazu Studios LLC
 * 
 * Catfish is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as 
 * published by the Free Software Foundation, either version 3 of 
 * the License, or (at your option) any later version.
 * 
 * Catfish is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with Catfish.  If not, please visit:
 *  
 * http://www.gnu.org/licenses/
 *  
 */
package com.namazustudios.catfish.utility;

import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;

import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Transaction;
import com.google.appengine.api.memcache.MemcacheService;
import com.google.inject.Inject;
import com.namazustudios.catfish.Catfish;
import com.namazustudios.catfish.annotation.Delete;
import com.namazustudios.catfish.annotation.PostPut;

public abstract class AbstractDataObject {

    @Inject
    transient private Catfish catfish;

    @Inject
    transient private MemcacheService memcache;

    @Inject(optional = true)
    private Logger logger = Logger.getLogger(AbstractDataObject.class.getName());

    protected final Catfish getCatfish() {

        if (catfish == null) {
            throw new IllegalStateException("Object " + this
                    + " not bound to instance of Catfish.");
        }

        return catfish;
    }

    /**
     * Puts this object into the datastore.
     */
    public final void put() {
        getCatfish().put(this);
    }

    /**
     * Puts this object into the datastore using the given transaction.
     * 
     * @param transaction
     */
    public final void put(Transaction transaction) {
        getCatfish().put(transaction, this);
    }

    /**
     * Gets this object from the datastore. If the object was already fetched,
     * it fetches the fields again.
     * 
     * @throws EntityNotFoundException
     *             if the entity could not be found in the datastore
     */
    public final void delete() {
        getCatfish().delete(this);
    }

    /**
     * Deletes this object from the datastore using the given transaction.
     * 
     * @param transaction
     *            the transaction
     */
    public final void delete(Transaction transaction) {
        getCatfish().delete(transaction, this);
    }

    /**
     * Invalidates the parent object from the memory cache. 
     */
    @Delete
    @PostPut
    @SuppressWarnings("unused")
    private final void invalidateParent() {
        Key key;
        Set<Object> invalid = new HashSet<Object>();

        if (!getCatfish().isCacheable(this)) {
            return;
        }

        key = getCatfish().getKey(this);

        if (key == null) {
            return;
        }

        while ((key = key.getParent()) != null) {
            invalid.add(key);
            logger.finer("Expiring memcached object: " + key);
        } 

        memcache.deleteAll(invalid);

    }
}
